package com.gframework.boot.mvc.controller.errcode;

import org.springframework.core.NestedCheckedException;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.core.NestedIOException;
import org.springframework.core.NestedRuntimeException;
import org.springframework.lang.Nullable;

import com.gframework.boot.mvc.controller.protocal.basic.ServerResponse;

/**
 * 异常信息封装异常类.
 * <p>本类最大的特点就是构造速度极快，不用担心实例化造成的性能浪费，但是无法获取到异常堆栈信息。
 * 它仅仅是用来表示某种已知异常信息的
 * <p>同时本类和{@link ServerResponse}存在关联，可以直接通过本类对象获取到ServerResponse类对象用于controller返回。
 * 
 * @since 1.0.0
 * @author Ghwolf
 * 
 * @see ErrorCode
 * @see NestedRuntimeException
 * @see NestedExceptionUtils
 * @see NestedIOException
 * @see NestedCheckedException
 */
public class ErrorCodeException extends RuntimeException {
	private static final long serialVersionUID = -6567387863493481232L;
	/**
	 * 状态码
	 */
	private final int errorCode ;
	/**
	 * 对应http状态码，默认是417
	 */
	private final int httpCode ;
	/**
	 * 默认body对象
	 */
	private final ServerResponse defaultResponse ;
	
	/**
	 * 专用于ErrorCodeException的ServerResponse，主要时为了给返回值添加一个特殊标记，以证明这是一个已知错误，可以直接通过message获取错误信息！
	 * <p>同时这也是一个不可修改的response对象
	 * @since 2.0.0
	 * @author Ghwolf
	 *
	 */
	@SuppressWarnings("serial")
	class ErrorCodeServerResponse extends ServerResponse {

		public ErrorCodeServerResponse() {
			super();
		}

		public ErrorCodeServerResponse(int status, String message, Object data) {
			super(status, message, data);
		}

		public ErrorCodeServerResponse(int status, String message) {
			super(status, message);
		}
		
		/**
		 * 返回体会增加一个knownError=true的标识，表示这是一个已知错误，可以直接通过message获取错误信息
		 * @return 一定返回true
		 */
		public boolean isKnownError(){
			return true ;
		}
		
		@Override
		public void setData(Object data) {
			// ignore
		}

		@Override
		public void setMessage(String message) {
			// ignore
		}

		@Override
		public void setStatus(int status) {
			// ignore
		}
	}
	
	/**
	 * 构造一个包含异常描述信息的异常对象
	 * 
	 * @param msg 异常描述信息
	 */
	public ErrorCodeException(int errorCode,String msg) {
		this(errorCode,ErrorCode.DEFAULT_EXCEPTION_TYPE_HTTP_STATUS,msg);
	}
	/**
	 * 构造一个包含异常描述信息和对应http状态码的异常对象
	 * 
	 * @param msg 异常描述信息
	 */
	public ErrorCodeException(int errorCode,int httpCode,String msg) {
		super(msg);
		this.httpCode = httpCode;
		this.errorCode = errorCode ;
		this.defaultResponse = new ErrorCodeServerResponse(errorCode, msg);
	}
	
	/**
	 * 获取异常状态码
	 * @return 返回错误状态码
	 */
	public int getErrorCode() {
		return this.errorCode;
	}
	
	/**
	 * 获取异常状态码对应的http状态码
	 * @return 返回http状态码
	 */
	public int getHttpCode() {
		return this.httpCode;
	}
	
	/**
	 * 获取默认的{@link ServerResponse}类对象.
	 * <p>使用此方法通常可以获得更好的性能
	 * @return 返回ServerResponse类对象
	 */
	public final ServerResponse response() {
		return defaultResponse;
	}
	
	/**
	 * 创建与此异常状态有关的{@link ServerResponse}类对象.
	 * <p>如果你没有特别的自定义描述信息，那么可以调用{@link #response()}方法来获得更好的性能。
	 * @param message 描述信息
	 * @return 返回ServerResponse类对象
	 */
	public final ServerResponse response(String message) {
		return new ServerResponse(this.errorCode,message);
	}

	/**
	 * 获取具有与当前异常类相同的状态码，但是可以自定义描述信息的异常类对象.
	 * 
	 * @param message 描述信息
	 * @return 返回当前状态码对应的具有指定描述信息的异常对象
	 */
	public final ErrorCodeException exception(@Nullable String message) {
		return new ErrorCodeException(this.errorCode,message);
	}
	
	@Override
	public Throwable getCause() {
		return null ;
	}
	
	@Override
	public Throwable fillInStackTrace() {
		return this ;
	}

}
